package org.gm.mybatis.ext.util;

import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class StringHelper {
	// 日期格式化匹配正则
	private static String DATE_REG[] = {
			"\\d{4}-\\d{2}-\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}\\.\\d{3}",
			"\\d{4}-\\d{2}-\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}",
			"\\d{4}-\\d{2}-\\d{2}\\s{1}\\d{2}:\\d{2}",
			"\\d{4}-\\d{2}-\\d{2}\\s{1}\\d{2}", "\\d{4}-\\d{2}-\\d{2}",
			"\\d{8}\\s{1}\\d{9}", "\\d{8}\\s{1}\\d{6}", "\\d{8}\\s{1}\\d{4}",
			"\\d{8}\\s{1}\\d{2}", "\\d{8}",
			"\\d{2}\\/\\d{2}\\/\\d{4}\\s{1}\\d{2}:\\d{2}:\\d{2}\\.\\d{3}",
			"\\d{2}\\/\\d{2}\\/\\d{4}\\s{1}\\d{2}:\\d{2}:\\d{2}",
			"\\d{2}\\/\\d{2}\\/\\d{4}\\s{1}\\d{2}:\\d{2}",
			"\\d{2}\\/\\d{2}\\/\\d{4}\\s{1}\\d{2}", "\\d{2}\\/\\d{2}\\/\\d{4}",
			"\\d{4}\\/\\d{2}\\/\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}\\.\\d{3}",
			"\\d{4}\\/\\d{2}\\/\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}",
			"\\d{4}\\/\\d{2}\\/\\d{2}\\s{1}\\d{2}:\\d{2}",
			"\\d{4}\\/\\d{2}\\/\\d{2}\\s{1}\\d{2}", "\\d{4}\\/\\d{2}\\/\\d{2}",
			"\\d{4}\\.\\d{2}\\.\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}\\.\\d{3}",
			"\\d{4}\\.\\d{2}\\.\\d{2}\\s{1}\\d{2}:\\d{2}:\\d{2}",
			"\\d{4}\\.\\d{2}\\.\\d{2}\\s{1}\\d{2}:\\d{2}",
			"\\d{4}\\.\\d{2}\\.\\d{2}\\s{1}\\d{2}", "\\d{4}\\.\\d{2}\\.\\d{2}",
			"\\d{4}年\\d{2}月\\d{2}日\\s{1}\\d{2}时\\d{2}分\\d{2}秒\\d{3}毫秒",
			"\\d{4}年\\d{2}月\\d{2}日\\s{1}\\d{2}时\\d{2}分\\d{2}秒",
			"\\d{4}年\\d{2}月\\d{2}日\\s{1}\\d{2}时\\d{2}分",
			"\\d{4}年\\d{2}月\\d{2}日\\s{1}\\d{2}时", "\\d{4}年\\d{2}月\\d{2}日" };
	// 日期格式化匹配格式
	private static String DATE_FORMATER[] = { "yyyy-MM-dd HH:mm:ss.SSS",
			"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH",
			"yyyy-MM-dd", "yyyyMMdd HHmmssSSS", "yyyyMMdd HHmmss",
			"yyyyMMdd HHmm", "yyyyMMdd HH", "yyyyMMdd",
			"MM/dd/yyyy HH:mm:ss.SSS", "MM/dd/yyyy HH:mm:ss",
			"MM/dd/yyyy HH:mm", "MM/dd/yyyy HH", "MM/dd/yyyy",
			"yyyy/MM/dd HH:mm:ss.SSS", "yyyy/MM/dd HH:mm:ss",
			"yyyy/MM/dd HH:mm", "yyyy/MM/dd HH", "yyyy/MM/dd",
			"yyyy.MM.dd HH:mm:ss.SSS", "yyyy.MM.dd HH:mm:ss",
			"yyyy.MM.dd HH:mm", "yyyy.MM.dd HH", "yyyy.MM.dd",
			"yyyy年MM月dd日 HH时mm分ss秒SSS毫秒", "yyyy年MM月dd日 HH时mm分ss秒",
			"yyyy年MM月dd日 HH时mm分", "yyyy年MM月dd日 HH时", "yyyy年MM月dd日" };

	/**
	 * 自动日期字符串解析为日期格式
	 * 
	 * @param param
	 * @return
	 * @throws Exception
	 */
	public static Date parseDate(String param) throws Exception {
		int index = 0;
		for (index = 0; index < DATE_REG.length; index++) {
			Pattern pattern = Pattern.compile(DATE_REG[index]);
			Matcher matcher = pattern.matcher(param);
			if (matcher.find()) {
				break;
			}
		}
		if (index == DATE_REG.length) {
			return null;
		} else {
			SimpleDateFormat format = new SimpleDateFormat();
			format.applyPattern(DATE_FORMATER[index]);
			return format.parse(param);
		}
	}

	/**
	 * 日期格式化为相应格式的字符串
	 * 
	 * @param date
	 *            日期数据
	 * @param reg
	 *            字符串格式化的格式<br/>
	 *            --------------------------------------<br/>
	 *            0 yyyy-MM-dd HH:mm:ss.SSS<br/>
	 *            1 yyyy-MM-dd HH:mm:ss<br/>
	 *            2 yyyy-MM-dd HH:mm<br/>
	 *            3 yyyy-MM-dd HH<br/>
	 *            4 yyyy-MM-dd<br/>
	 *            5 yyyyMMdd HHmmssSSS<br/>
	 *            6 yyyyMMdd HHmmss<br/>
	 *            7 yyyyMMdd HHmm<br/>
	 *            8 yyyyMMdd HH<br/>
	 *            9 yyyyMMdd<br/>
	 *            10 MM/dd/yyyy HH:mm:ss.SSS<br/>
	 *            11 MM/dd/yyyy HH:mm:ss<br/>
	 *            12 MM/dd/yyyy HH:mm<br/>
	 *            13 MM/dd/yyyy HH<br/>
	 *            14 MM/dd/yyyy<br/>
	 *            15 yyyy/MM/dd HH:mm:ss.SSS<br/>
	 *            16 yyyy/MM/dd HH:mm:ss<br/>
	 *            17 yyyy/MM/dd HH:mm<br/>
	 *            18 yyyy/MM/dd HH<br/>
	 *            19 yyyy/MM/dd<br/>
	 *            20 yyyy.MM.dd HH:mm:ss.SSS<br/>
	 *            21 yyyy.MM.dd HH:mm:ss<br/>
	 *            22 yyyy.MM.dd HH:mm<br/>
	 *            23 yyyy.MM.dd HH<br/>
	 *            24 yyyy.MM.dd<br/>
	 *            25 yyyy年MM月dd日 HH时mm分ss秒SSS毫秒<br/>
	 *            26 yyyy年MM月dd日 HH时mm分ss秒<br/>
	 *            27 yyyy年MM月dd日 HH时mm分<br/>
	 *            28 yyyy年MM月dd日 HH时<br/>
	 *            29 yyyy年MM月dd日<br/>
	 *            --------------------------------------
	 * @return
	 */
	public static String formatDate(Date date, int reg) {
		SimpleDateFormat format = new SimpleDateFormat();
		format.applyPattern(DATE_FORMATER[reg]);
		return format.format(date);
	}

	/**
	 * 根据自定义规则格式化日期字符串
	 * 
	 * @param date
	 * @param pattern
	 * @return
	 */
	public static String formatDate(Date date, String pattern) {
		SimpleDateFormat format = new SimpleDateFormat();
		format.applyPattern(pattern);
		return format.format(date);
	}

	/**
	 * 日期增加天数
	 * 
	 * @param date
	 *            日期时间
	 * @param addition
	 *            增加天数
	 * @return 增加后的日期时间
	 */
	public static Date dateAddition(Date date, int addition) {
		long time = date.getTime();
		time = time + (addition * 24 * 60 * 60 * 1000);
		date.setTime(time);
		return date;
	}

	/**
	 * 日期减少天数
	 * 
	 * @param date
	 *            日期时间
	 * @param sub
	 *            减少天数
	 * @return 减少后的日期时间
	 */
	public static Date dateSubtraction(Date date, int sub) {
		long time = date.getTime();
		time = time - (sub * 24 * 60 * 60 * 1000);
		date.setTime(time);
		return date;
	}

	/**
	 * 替换字符串中的空白字符
	 * 
	 * @param before
	 *            原字符串
	 * @return 替换后的字符串
	 */
	public static String replaceBlank(String before) {
		String after = "";
		Pattern p = Pattern.compile("/t|/r|/n");
		Matcher m = p.matcher(before);
		after = m.replaceAll("");
		return after;
	}

	/**
	 * 生成UUID数据
	 * 
	 * @return UUID数据
	 */
	public static String uuid() {
		return java.util.UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 字符串MD5加密
	 * 
	 * @param source
	 *            原字符串
	 * @return 加密字符串
	 */
	@SuppressWarnings("finally")
	public static String md5String(String source) {
		String md5 = null;
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			// 返回实现指定摘要算法的 MessageDigest 对象
			MessageDigest md = MessageDigest.getInstance("MD5");
			// 使用utf-8编码将originstr字符串编码并保存到source字节数组
			byte[] bt = source.getBytes("utf-8");
			// 使用指定的 byte 数组更新摘要
			md.update(bt);
			// 通过执行诸如填充之类的最终操作完成哈希计算，结果是一个128位的长整数
			byte[] tmp = md.digest();
			// 用16进制数表示需要32位
			char[] str = new char[32];
			for (int i = 0, j = 0; i < 16; i++) {

				// j表示转换结果中对应的字符位置

				// 从第一个字节开始，对 MD5 的每一个字节

				// 转换成 16 进制字符

				byte b = tmp[i];

				// 取字节中高 4 位的数字转换

				// 无符号右移运算符>>> ，它总是在左边补0

				// 0x代表它后面的是十六进制的数字. f转换成十进制就是15

				str[j++] = hexDigits[b >>> 4 & 0xf];

				// 取字节中低 4 位的数字转换

				str[j++] = hexDigits[b & 0xf];

			}
			md5 = new String(str);// 结果转换成字符串用于返回

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			return md5;
		}

	}

	/**
	 * 在指定目录中查找数据表对应的数据表实体类
	 * 
	 * @param basePath
	 *            指定路径
	 * @param fileName
	 *            数据表实体名称
	 * @return 相对目录
	 */
	public static String findTable(String basePath, String fileName) {
		String self = new String();
		File file = new File(basePath);
		File subs[] = file.listFiles();
		for (File sub : subs) {
			if (sub.isDirectory()) {
				self = findTable(basePath + "/" + sub.getName(), fileName);
			} else if (sub.getName().equals(fileName)) {
				self = ".";
			}
			if (!self.equals("")) {
				break;
			}
		}
		if (!self.equals("")) {
			self = "." + file.getName() + self;
		}
		return self;
	}

	/**
	 * java名称转数据库名称
	 * 
	 * @param javaName
	 *            java名称
	 * @return 数据库名称
	 */
	public static String javaNameToDbName(String javaName) {
		StringBuffer dbName = new StringBuffer();
		char[] nch = javaName.toCharArray();
		for (char c : nch) {
			int ascii = (int) c;
			if (ascii >= 65 && ascii <= 90) {
				dbName.append("_");
			}
			dbName.append(String.valueOf(c).toLowerCase());
		}
		return dbName.toString();
	}

	/**
	 * 数据库名称转Java名称
	 * 
	 * @param dbName
	 *            数据库名称
	 * @return Java名称
	 */
	public static String dbNameToJavaName(String... dbName) {
		StringBuffer javaName = new StringBuffer();
		if (dbName[0].indexOf("_") == 0)
			return dbName[0];
		String[] dname = dbName[0].split("_");
		for (int index = 0; index < dname.length; index++) {
			if (index == 0 && dbName.length == 1) {
				javaName.append(dname[index]);
			} else {
				String first = dname[index].substring(0, 1);
				String other = dname[index].substring(1);
				javaName.append(first.toUpperCase());
				javaName.append(other);
			}
		}
		return javaName.toString();
	}

	/**
	 * 判断字符串非空
	 * 
	 * @param source
	 * @return
	 */
	public static boolean notEmpty(String source) {
		return !(isEmpty(source));
	}

	public static boolean notEmpty(StringBuffer source) {
		return !(isEmpty(source));
	}

	public static boolean notEmpty(StringBuilder source) {
		return !(isEmpty(source));
	}

	public static boolean notEmpty(Object source) {
		return !(isEmpty(source));
	}

	/**
	 * 判断字符串为空
	 * 
	 * @param source
	 * @return
	 */
	public static boolean isEmpty(String source) {
		return (source == null || "".equals(source.trim())
				|| "null".equals(source.trim()) || "undefined".equals(source
				.trim()));
	}

	public static boolean isEmpty(StringBuffer source) {
		return (source == null || "".equals(source.toString().trim())
				|| "null".equals(source.toString().trim()) || "undefined"
					.equals(source.toString().trim()));
	}

	public static boolean isEmpty(StringBuilder source) {
		return (source == null || "".equals(source.toString().trim())
				|| "null".equals(source.toString().trim()) || "undefined"
					.equals(source.toString().trim()));
	}

	public static boolean isEmpty(Object source) {
		return (source == null || "".equals(source.toString().trim())
				|| "null".equals(source.toString().trim()) || "undefined"
					.equals(source.toString().trim()));
	}

	/**
	 * 判断是否为数字
	 * 
	 * @param src
	 * @return
	 */
	public static boolean isNumeric(String src) {
		if (src == null || src.equals("")) {
			return false;
		} else {
			Pattern pattern = Pattern.compile("^(-?\\d+)(\\.\\d+)?$");
			Matcher isNum = pattern.matcher(src);
			if (!isNum.matches()) {
				return false;
			}
			return true;
		}
	}

	/**
	 * 判断是否为布尔
	 * 
	 * @param src
	 * @return
	 */
	public static boolean isBool(String src) {
		if (src == null || src.equals("")) {
			return false;
		} else if (src.trim().equals("true") || src.trim().equals("false")) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 格式化数字后面保留六位小数
	 * 
	 * @param number
	 * @return
	 */
	public static String numberFormatWithTowDigit(Object number) {
		// BigDecimal decimal = null;
		// if(number instanceof BigDecimal){
		// decimal = (BigDecimal)number;
		// }
		// if(number instanceof Double){
		// decimal = new BigDecimal((Double)number);
		// }
		// decimal.setScale(2);
		// return decimal;
		DecimalFormat fmt = new DecimalFormat("#################0.00");
		return fmt.format(number);
		// NumberFormat format = NumberFormat.getInstance();
		// format.setMaximumFractionDigits(2);
		// format.setMinimumFractionDigits(2);
		// return format.format(number);
	}

	/**
	 * 获取某个类型的泛型类型
	 * @param clazz 原类型
	 * @param index 泛型索引
	 * @return
	 */
	public static Class<?> getSuperClassGenricType(final Class<?> clazz, final int index) {

		// 返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		// 返回表示此类型实际类型参数的 Type 对象的数组。
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}

		return (Class<?>) params[index];
	}
}
